%d) Escribir una rutina que se encargue de limpiar la pantalla y pintar la primer y ultima
% ́
%l ́
%ınea de color de fondo negro y letras blancas. Para este ejercicio se debe escribir en la
%pantalla usando el segmento declarado en el punto anterior. (para los pr ́ximos 

\subsubsection {Ejercicio 1}
\indent Este ejercicio consiste en armar la GDT, preparar el kernel para saltar a modo protegido e imprimir cosas en pantalla.\\
\indent La primera entrada de la GDT es una entrada nula, luego, cargamos los descriptores correspondientes a cada nivel (0, 2 y 3) para c\'odigo y datos respectivamente. Notar que la diferencia entre cada par de segmentos en el mismo nivel es \'unicamente el campo tipo. Por ejemplo, un descriptor de segmento de c\'odigo de nivel 0 es de la forma:\\
\begin{itemize}
  \item limite = 0x7FFFF, es decir, completamos los campos limit(0:15) con 0xFFFF y limit(16:19) con 0x7 y activamos granularidad para que direccione a 2 GB, es decir, que extienda el límite ingresado.
  \item base = 0x00000000, es decir, completamos los campos base(0:15) con 0x0000, base(23:16) con 0x00 y base(31:24) con 0x00
  \item En el tipo le pusimos 0xA para indicar que es de código y permitir que se pueda leer y ejecutar
  \item en el bit de sistema le pusimos 1 para indicar que no es de sistema
  \item le asignamos DPL 0
  \item lo marcamos como presente
  \item en el campo AVL pusimos 0 al igual que en el campo ``l'' pues trabajamos con la arquitectura de 32 bits y como trabajamos con segmentos de 32 bits marcamos el bit DB como uno.
\end{itemize}
Para definir el segmento de datos nivel 0 la inizializaci\'on es muy similar, solo difiere en el campo tipo, donde vez de ser 0xA es 0x2:\\
Para definir el segmento de c\'odigo nivel 2 la inicializaci\'on tambiene s muy parecida, excepto por el campo dpl, que ahora es 0x2 (pu\'es es otro nivel) en vez de 0x0.\\
\indent El resto de las definiciones es an\'aloga.\\ 

\indent Una vez hecho esto, debíamos preparar todo lo necesario para pasar a modo protegido y setear la pila del kernel en la posición 0x20000.\\
\indent Para pasar a modo protegido, lo que realizamos fue:
\begin{itemize}
 \item Deshabilitar las interrupciones, usando cli
 \item Habilitamos A20 (llamando a la rutina habilitar\_A20)
 \item Cargamos la gdt utilizando la instrucción lgdt[GDT\_DESC], donde GDT\_DESC es la base de la GDT
 \item Seteamos el bit PE del registro CR0 realizando un OR entre lo que contiene este registro y 0x1
 \item Finalmente realizamos el salto a 0x8:modoProtegido, pues en la posición 0x8 de la GDT se encuentra el selector de código de nivel 0 y modoProtegido es la etiqueta donde empezamos a definir el código correspondiente al modo protegido.
\end{itemize}
Estando en modo protegido, seteamos los correspondientes registros de segmento de datos y el segmento extra para video (en fs). Además para setear la pila en la dirección 0x20000, una vez en modo protegido, cargamos los registros ebp y esp con el valor 0x21000.\\
\indent Finalmente, para terminar el ejercicio, imprimimos en la primera y \'ultima l\'inea de pantalla (usando el segmento declarado para tal fin) los integrantes del grupo y el nombre.


\subsubsection{Ejercicio 2}
\indent Lo que hicimos fue rellenar la IDT para las entradas 0-19 (20 a 31 estan reservadas), y las correspondientes para el ej 5 (32 : reloj, 33 teclado y 0x80 para sistema.\\
\indent Todas estas entradas fueron inicializadas con los siguientes valores:
\begin{itemize}
 \item En el campo offset(15:0) se colocan los últimos 2 bytes de la dirección donde se encuentra la rutina de atención de la interrupción en cuestión.
 \item En el selector de segmento ponemos 0x0008, que corresponde a un segmento de código de nivel 0.
 \item En los atributos de la entrada IDT usuario colocamos 0xEE00 (macro ID\_ENTRY2) que indica que estamos trabajando con una interrupt gate, de tamaño 32 bits, DPL 3 y presente.
 \item En los atributos de la entrada IDT supervisor colocamos 0x8E00 (macro ID\_ENTRY2 que indica que estamos trabajando con una interrupt gate, de tamaño 32 bits, dpl 0 y presente.
 \item En el campo offset(32:16) colocamos los primero 2 bytes de la dirección donde se encuentra la rutina de atención de la interrupción en cuestión.
\end{itemize}

\indent Luego, completamos en el archivo isr.asm, los headers de las rutinas de atención para todas estas entradas de IDT. Para cada uno, imprimimos en pantalla a qué interrupción se está llamando utilizando la macro ISR.\\

\indent Una vez realizado todo esto, para probar el uso de estas rutinas por parte del procesador,  realizamos una división por cero, y efectivamente, se nos imprime en pantalla el mensaje de ``Divide Error''.

\subsubsection{Ejercicio 3}
\indent La inicializaci\'on del directorio y la tabla de p\'aginas la completamos sin hacer uso de la funci\'on inicializar\_dir\_kernel sino que lo hamos directamente en kernel.asm de la siguiente forma:
\begin{itemize}
\item Inicializamos todas las posiciones del Page Directory (PD) en 0x00000002.
\item Apuntamos la primer página de PD a la page table y seteamos los bits de presente y lectura/escritura
\item Realizamos el identity mapping (vinculamos la posición 0 con la dirección de memoria 0x0000, la 1 con la 0x1000) para las 164 cada p\'aginas de la PAGE TABLE y activamos la lectura/escritura y el bit de presencia de cada página.
\end{itemize}

\indent Vale destacar que para cumplir con lo que pide el enunciado con respecto a donde inicializar las tablas, esto lo cumplimos al utilizar como posición inicial del PD a la 0x21000 y a la del PT 0x22000 (usando las constantes KERNEL\_PAGE\_DIR y KERNEL\_PAGE\_TABLE en defines.h)\\

\indent Para activar paginación, lo que realizamos fue cargar en el camó base del cr3 la dirección del PD y setear el bit de paginación (or usando 0x80000000) del cr0.\\

\indent La rutina para escribir el nombre del grupo en la primera y \'ultima l\'inea de la pantalla ya lo hab\'iamos hecho en el ejercicio 1.4\\

\subsubsection{Ejercicio 4}
%a) Escribir una rutina (inicializar mmu) que se encargue de inicializar las estructuras necesarias y limpiar el mapa de memoria en pantalla.
\indent Para completar la rutina que inicializa la mmu, lo único que hicimos fue inicializarlos directorios de las 5 tareas que correrá el sistema. Esto lo hicimos utilizando la función inicializar\_tarea\_jugador e inicializar\_tarea\_arbitro, cuya implementación la explicaremos más adelante. Notar que para cada tarea se llama a la funci\'on correspondiente con los par\'ametros correspondientes a dicha tarea (direcci\'on directorio p\'aginas, direcciones f\'iscas,etc).\\

%b) Escribir una rutina (inicializar\_tarea\_jugador) encargada de inicializar un directorio de ṕginas y tablas de p ́ginas para una tarea jugador.
\indent Para implementar la inicializar\_tarea\_jugador, primero seteamos la ubicación del directorio de páginas (funci\'on inicializar\_directorio) y de la tabla de páginas para la tarea que corresponda. Luego seteamos la \'unica entrada del directorio de páginas de la tarea en 0x00000007 para permitir lectura y escritura. Una vez hcho esto, apuntamos la base de la primer entrada de la misma a la tabla de páginas de la tarea, permitiendo lectura y escritura, indicando que la tabla está presente y que es de nivel usuario.\\
\indent Ahora inicializamos la tabla de páginas de la tarea realizando identity mapping y activando los bits de presencia, lectura/escritura y indicando que es de nivel supervisor. (funci\'on inicializar\_paginas\_de\_kernel\\
\indent Después realizamos la copia de una página de 4k desde code\_src (variable que apunta a la dirección de código de la tarea) hacia code\_pa(dirección f\'isica de la tarea).\\
\indent Usando la función de mmu\_mapear\_página, mapeamos las siguientes direcciones con nivel de usuario:
\begin{enumerate}
 \item La dirección 0x3A0000 con la dirección que f\'isica que le corresponde al código de la tarea.
 \item La dirección 0x3B0000 con la dirección que f\'isca que le corresponde a la pila de la tarea.
 \item La dirección 0x3C0000 con la dirección que f\'isca que le corresponde al tablero. Notar que en este mapeo se omite el bit de escritura.
\end{enumerate}

%c) Idem anterior pero la rutina inicializar\_tarea\_arbitro
\indent La rutina inicializar\_tarea\_arbitro es an\'aloga a la anterior con las diferencias:
\begin{itemize}
\item adem\'as de los mapeos que hacen las tareas regulares, el arbitro hace un mapeo (mediante identity mapping) para la memoria de video. Dicho mapeo tiene como atributos el bit de supervisor, present y lectura/escritura, puesto que el arbitro es el \'unico que puede escribir en pantalla.
\end{itemize}

%d) Escribir la funcion : mmu_mapear_pagina

\indent \textbf{Observación}: A la hora de utilizar la función de mm\_mapear\_pagina se nos hizo más práctico poder pasar como parámetro los atributos correspondientes a las entradas de la tabla de páginas, es por esto que agregamos un parámetro a la aridad de esta función llamado ``attr'' que representa el atributo de la entrada.\\

\indent La función mmu\_mapear\_pagina permite mapear la pagina f\'isica en la direcci\'on virtual utilizando cr3, todos estos pasados por par\'ametro. Primero ``tableIndex'' (bits 12-21) que representan el \'indice en la tabla de p\'aginas. Luego obtenemos el ``diretory\_index'' (bits 22-31) que representan la entrada en el directorio de p\'aginas. Sumando ``diretory\_index'' a cr3, obtenemos la entrada correspondiente en el directory (variable ``pd\_entry''). Alineamos esta direcci\'on a 4k y nos da el puntero a nuestra tabla de p\'aginas (variable ``page\_table\_ptr''). Usando la variable ``page\_index'' antes calculada, lo sumamos a ``page\_table\_ptr'' y obtenemos la p\'agina buscada. Finalmente, a ese puntero le asignamos como valor la direcci\'on f\'isica pasada como par\'ametro + los atributos (tambi\'en pasados como par\'ametro).\\

%e) Construir un mapa de memoria para tareas e intercambiarlo con el del kernel, luego cambiar el color del fondo del primer caracter de la pantalla y volver a la normalidad.
\indent Para el punto ``e'' del ejercicio, definimos una funci\'on ``test\_paging'' que va a hacer justamente lo que pide el ejercicio, tomando como par\'ametro un directorio de p\'aginas para intercambiar con el del kernel. Dicha funci\'on es llamada al termino de ``mmu\_inicializar''. Esta funci\'on va a guardar el CR3 del kernel (temporalmente en edx) y pisarlo con el que le pasaron como par\'ametro. Luego imprimimos en la primer posición del vector de memoria de video el mismo caracter que tenía antes pero con otro fondo y pusimos un breakpoint. Ejecutamos bochs y chequeamos que el CR3 haya cambiado, lo cual sucedió. Luego restauramos el CR3 original, pusimos un nuevo breakpoint y nuevamente chequeamos que el CR3 sea el mismo que el del principio. Efectivamente, esto fue así.

\subsubsection{Ejercicio 5}
%a) Completar las entradas necesarias en la IDT para asociar una rutina a la interrupci ́n del reloj, otra a la interrupci ́n de 
%teclado y por ultimo una a la interrupci ́n 0x80.

\indent En el punto 3 hab\'iamos agregado 3 entradas extras en la IDT : la 32, la 33 y la 0x80 y 0x90. Las 2 primeras las completamos de la misma forma que hicimos con las interrupciones del procesador en el punto 3. Es decir, para completar la entrada de IDT pusimos como offset el campo offset(15:0) la dirección donde se encuentra la rutina de atención de la interrupción en cuestión, en el selector de segmento ponemos 0x08 (que corresponde a un segmento de código de nivel 0) y en los atributos colocamos 0x8E00 (que indica que estamos trabajando con una interrupt gate, de tamaño 32 bits, dpl 0 y presente). Y las entradas de IDT correspondientes a las interrupciones 0x80 y 0x90, la completamos exactamente de la misma forma, pero poniendo el dpl en 3 (o sea attrs en 0xEE00), pues son interrupciones de tareas.\\

%b) Escribir la rutina asociada a la interrupci ́n del reloj, para que por cada tick llame a la funci ́n proximo reloj. La misma se encarga de mostrar, por cada vez que se llama, la animaci ́n de un cursor rotando. En la figura 6 se detalla en que posici ́n de la pantalla aparece el reloj. La funci ́n proximo reloj est ́ definida en isr.asm.

\indent Para completar la rutina del reloj, completamos en el archivo isr.asm la entrada \_isr32 de la siguiente forma:primero desactivamos interrupciones, preservamos registros y EFLAGS,  llamamos a fin\_intr\_pic1 y luego llamamos a la rutina de proximo\_reloj. Una vez hecho esto, restauramos el valor del registro EFLAGS y de los otros, activamos interrupciones y hacemos iret. Más adelante, tuvimos que modificar esta rutina para agregar atributos y funciones del scheduler.\\

En el caso de la rutina de teclado, realizamos lo siguiente:
\begin{enumerate}
	\item desactivamos interrupciones
	\item preservamos registros y EFLAGS
	\item llamamos a fin\_intr\_pic1
	\item movemos al registro del inout el valor 0x60
	\item checkeamos si la tecla presionada es P o S. Esto lo hacemos con un compare entre el valor de entrada del inout y el scancode de la tecla P. De no ser iguales, se salta a una rutina que chequea si S. Si no es ninguna de esas dos teclas, no se hace nada.
	\item restauramos EFLAGS y registros
	\item activamos interrupciones
	\item iret
\end{enumerate}

Para la rutina de la \_isr90 lo que hicimos en un principio fue:  deshabilitar interrupciones, preservar EFLAGS y registros, llamar a fin\_intr\_pic1, mover el valor 0x2A a eax, restaurar EFLAGS y registros, habilitar interrupciones y iret.

\subsubsection{Ejercicio 6}
%a) Definir 7 entradas en la GDT. Una reservada para la tarea inicial, otra para la tarea IDLE y las 5 restantes para cada una de las tareas que se van a ejecutar en el sistema.
\indent Como primer paso, para este ejercicio difinimos las 7 nuevas entradas en la gdt dejando algunos valores para completar desde tss.c (pu\'es valores din\'amicos no pueden estar en la inicializaci\'on). Ellon son :\\
\begin{itemize}
	\item base\_0\_15
	\item base\_23\_16
	\item base\_31\_24
	\item limit\_0\_15
\end{itemize}
La raz\'on por la cual se pospone la inicializaci\'on de esos valores es porque primero necesitamos inicializada la tabla ``tsss'', la cual se hace durante el llamado a la funci\'on ``tss\_inicializar''.\\

%b) Completar la entrada de la TSS correspondiente a la tarea IDLE. Esta informaci ́n se encuentra en el archivo TSS.C. La tarea IDLE se encuentra en la direcci ́n 0x00010000. La pila se alojar ́ en la p ́gina 0x0003F000 y ser ́ mapeada con identity mapping. Esta tarea est ́ compilada para ser ejecutada desde la direcci ́n 0x003A0000 y la misma debe compartir el mismo CR3 que el kernel.
\indent Para inicializar la TSS de la tarea IDLE, realizamos una función (tss\_initializar\_tarea\_idle) que mapea a dirección virtual del código de la tarea con la dirección física del código y completa la TSS con los siguientes valores:
\begin{itemize}
	\item En donde se almacena el CR3 se guarda el del kernel;
	\item Se ubica la dirección del eip en donde se encuentra el código de la tarea(0x3A000);
	\item Se setean los EFLAGS en 0x202, es decir con interrupciones en 1 y ;
	\item Como la tarea IDLE corre en nivel 0, se mantienen los registros de segmentación del kernel;
	\item Se apuntan el esp0, el esp y el ebp a donde se aloja la pila de la tarea IDLE, es decir, a la dirección 0x3F000+0x1000
\end{itemize}

%c) Completar el resto de las entradas del arreglo de las TSS definidas con los valores correspondientes a las tareas que correr ́ el sistema. El c ́digo de las tareas se encuentra a partir de la direcci ́n 0x00011000 ocupando una p ́gina de 4kb cada una. El mismo debe ser mapeado a partir de la direcci ́n 0x003A0000.

\indent La función tss\_inicializar\_tarea tiene como fin completar la TSS de una tarea en particular, la que se pasa por parámetro y lo hace de la siguiente manera:\\
\begin{itemize}
	\item Guarda como cr3 la dirección del directorio de páginas de la tarea;
	\item Se sitúa la dirección del eip a donde se encuentra la tarea;
	\item EFLAGS nuevamente en 0x202;
	\item Como las tareas corren en nivel 3 y para cumplir con lo pedido, se almacenan los siguientes valores para los registros de segmentación:
		\begin{itemize}
		\item es = ss = ds = fs = gs = 0x33, que es un segmento de datos de nivel 3;
		\item cs = 0x2B, que es un segmento de código de nivel 3;
		\end{itemize}
	\item Tanto esp como ebp se ubican en la dirección de la pila de la tarea que es TASK\_STACK(0x3B000)+0x1000;
	\item El esp0 en  la dirección física de la pila de nivel 0 de la tarea.
	\item El ss de nivel 0 en el segmento de datos de nivel 0 ubicado en la posicipón 0x60;
\end{itemize}


\indent La función tss\_inicializar\_arbitro tiene como fin completar la TSS de la tarea arbitro :\\
\begin{itemize}
	\item CR3 = TASK\_5\_PAGE\_DIR;
	\item Se ubica la dirección del eip en donde se encuentra el código de la tarea(0x3A000);
	\item Se setean los EFLAGS en 0x202, es decir con interrupciones en 1 y ;
	\item es = ss = ds = fs = gs = 0x22, que es un segmento de datos de nivel 2;
	\item Se apuntan el esp0, el esp y el ebp a donde se aloja la pila de la tarea arbitro, es decir, a la dirección 0x3E000+0x1000
\end{itemize}

\indent Para la funci\'on tss\_initializar\_tarea\_inicial no nos interesa setear valores para su respectivo tss puesto que nunca se va a saltar a esa tarea, solo nos interesa setear los valores de la GDT que no pudimos setear en la inicializaci\'on.\\

\indent Para completar los descriptores anteriormente nombrados y los de las 5 tareas desde asm, utilizamos una función que se llama tss\_inicializar, la cual se encarga de llamar a :\\
\begin{itemize}
	\item tss\_initializar\_tarea\_inicial
	\item tss\_initializar\_tarea\_idle
	\item tss\_inicializar\_tarea    (para cada una de las 4 tareas que actuar\'an como jugadores)
\end{itemize}



%g) Escribir el c ́digo necesario para ejecutar la tarea IDLE, es decir, saltar intercambiando las TSS, entre la tarea inicial y la tarea IDLE.
\indent Una vez hecho todo eso, para ejecutar la tarea IDLE, primero llamamos a inicializar\_scheduler, que inicializa todas las estructuras necesarias para arrancar el scheduler. Posteriormente cargamos el selector de la tarea inicial en un registro, es decir, el 0x40 y lo cargamos en el task register. Luego de cargar el task register, hacemos un cambio de tareas pasando a la tarea idle mediante un \emph{0x48:0}. 
CPU correrá la tarea idle y cuando se produzca la próxima interrupción de reloj saltará a la primera tarea.

\subsubsection{Ejercicio 7}

\indent Inicializamos un arreglo con los \'indices de las tareas de la GDT, y un arreglo con los jugadores, inicialmente todos, pero este arreglo ira cambiando a medida que las tareas vayan muriendo, manteniendo solo a las tareas vivas.\\
\begin{itemize}
	\item tarea.actual = Idle, inicialmente arrancamos corriendo la tarea idle, porque como es una tarea neutra no modifica el comportamiento del scheduler.
	\item scheduler.cant\_jugadores\_vivos = 4, es la cantidad inicial de jugadores.
	\item scheduler.jugador\_actual\_index = 3, comienza en el jugador 4 (indice 3), asi en la proxima iteracion corre el primer jugador (indice 0).\\
\end{itemize}

\indent Implementamos la funci\'on sched\_proximo\_indice(), cuya funcionalidad es hacer el switcheo de tareas entre los jugadores y el arbitro, el mecanismo es intercalar una ejecuci\'on del \'arbitro con una ejecuci\'on de alg\'un jugador, estos \'ultimos se van turnando haciendo round-robin. Cuando el juego se encuentra finalizado(chequeando el estado en la funci\'on game\_estaTerminado()) retorna siempre el \'indice de la tarea idle.

\indent Modificamos las interrupciones 0x80 y 0x90, para que implemente los servicios del sistema especificados en la secci\'on 3.3 del enunciado. Una vez atendido el syscall se procede a llamar al scheduler para que realize el cambio de tarea.

\indent En cada interrupci\'on de reloj se incrementa el contador de ticks. En caso de que se haya alcanzado el quantum de la tarea en ejecuci\'on, se resetea el contador y se procede a desalojarla, llamando a la funci\'on \verb+sched_proximo_indice+ para obtener la pr\'oxima tarea y luego llamando a la funci\'on \verb+sched_jump()+ que realiza el cambio de contexto de la tarea. En caso de que la proxima tarea sea la misma que la que se estaba ejecutando, no se realiza acci\'on alguna, permitiendo que continue su ejecuci\'on.

\indent  Manejamos las rutinas de excepciones para cada tarea, en caso que haya un error se procede a eliminar la tarea del scheduler, se imprimi en pantalla el error en la linea de estado de la tarea y se llama de nuevo al scheduler para que defina la siguiente tarea a ejecutar.  


\subsubsection{Mapeo de p\'aginas on demand}

\indent Para proveer esta funcionalidad necesitamos inicializar ciertas estructuras de datos en memoria:
\begin{itemize}
	\item \verb+number_of_pages_per_task+ un arreglo de enteros con la cantidad de p\'aginas entregadas a cada tarea. Inicialmente contiene todos ceros.
	\item \verb+next_available_page_frame+ un puntero con la siguiente direcci\'on f\'isica disponible para mapear. Inicialmente toma el valor $0x164000$.
	\item \verb+pd_address_per_task+ un arreglo de tama\~no \textit{cantidad de tareas} con los punteros a los directorios de p\'agina de cada tarea.
\end{itemize}

\indent Atendemos la interrupci\'on 14 desde un procedimiento de assembler. Guardamos los registros de prop\'osito general con la instrucci\'on \textit{pushad} para mantener el estado de la tarea en ejecuci\'on.

\indent Obtenemos el n\'umero de la tarea mediante la funci\'on \verb+sched_jugador_actual+. De el registro \textit{CR2} obtenemos la direcci\'on de memoria que origin\'o el \textit{page fault} y calculamos cual ser\'ia el origen de p\'agina. Con estos dos datos invocamos a la funci\'on \verb+mmu_handle_page_fault+, escrito en C.

\indent Desde este procedimiento chequeamos que la direcci\'on de memoria pedida est\'e en el rango v\'alido (\textit{0x3D0000 - 0x3F000}). De ser asi, verificamos que la tarea no se haya excedido en su cantidad de p\'aginas pedidas. Si cumple con todas las condiciones mapeamos la direcci\'on virtual con la proxima direcci\'on fisica disponible (\verb+next_available_page_frame+). Finalmente se actualizan este \'ultimo valor con el pr\'oximo marco de pagina libre y se incrementa la cantidad de paginas servidas para esta tarea.

\indent De vuelta en assembler, si la funci\'on no tuvo exito se notifica en el estado de la tarea correspondiente la causa del error y se procede a eliminar la misma del scheduler. Luego, tanto si el resultado fue exitoso como si no, llamamos al scheduler para que ejecute la siguiente tarea.

\indent La rutina de atenci\'on finaliza reestableciendo los registros y haciendo un pop del \textit{error code}, de forma que al ejecutar \textit{iret} el \textit{EIP} de la tarea quede al tope de la pila.


\newpage
